<!DOCTYPE html>
<html lang="zh-CN">
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  
  
  <!-- 关键字 keywords -->
  
  <meta name="keywords" content="a,天赐,天赐の小站,博客">
  
  
  <title itemprop="name">JUC学习笔记-显式锁：ReentrantLock详解 | 天赐の小站</title>
  
    <link rel="shortcut icon" href="//fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/favicon.ico">
  
  <meta http-equiv="x-dns-prefetch-control" content="on">
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+SerifMerriweather|Merriweather+Sans|Source+Code+Pro|Ubuntu:400,700|Noto+Serif+SC" media="all">
  <link rel="dns-prefetch" href="//cdn.jsdelivr.net">
  <link rel="stylesheet" id="saukra_css-css" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/style.css" type="text/css" media="all">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/lib.min.css" media="all">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/font.css" media="all">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/insight.css" media="all">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/jquery.fancybox.min.css" media="all">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/zoom.css" media="all">
  <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/sharejs.css">
<!--   <link rel="stylesheet" id="saukra_css-css" href="https://2heng.xin/wp-content/cache/autoptimize/css/autoptimize_ad42a61f4c7d4bdd9f91afcff6b5dda5.css
" type="text/css" media="all"> -->
  <script>
  /*Initial Variables*/
  var mashiro_option = new Object();
  var mashiro_global = new Object();
  mashiro_option.NProgressON = true;
  /* 
   * 邮箱信息之类的东西可以填在这里，这些js变量基本都作用于sakura-app.js
   * 这样的设置仅是为了方便在基于PHP开发的主题中设置js变量，既然移植到了Node上，我想或许可以精简这一逻辑吧
   */
  mashiro_option.email_domain = "";
  mashiro_option.email_name = "";
  mashiro_option.cookie_version_control = "";
  mashiro_option.qzone_autocomplete = false;
  mashiro_option.site_name = "天赐の小站";
  mashiro_option.author_name = "天赐の小站";
  mashiro_option.site_url = "/";
  mashiro_option.v_appId = "VeenC2gYYyfSOq2rcCSmmruy-MdYXbMMI";
  mashiro_option.v_appKey = "F5kjyHdh4akqc7SDmfzQP8Qi";
  mashiro_option.v_notify = false;
  mashiro_option.v_verify = false;
  mashiro_option.v_placeholder = "你是我一生只会遇见一次的惊喜 ...";
  mashiro_option.v_avatar = "monsterid";
  mashiro_option.v_pageSize = "5" || 10;
  mashiro_option.mathjax = "0";
  mashiro_option.qq_api_url = "https://api.mashiro.top/qqinfo/"; 
  mashiro_option.qq_avatar_api_url = "https://api.mashiro.top/qqinfo/";

  // mashiro_option.jsdelivr_css_src = "https://cdn.jsdelivr.net/gh/moezx/cdn@3.4.5/css/lib.min.css";
  // mashiro_option.float_player_on = true;
  console.info("%c Blog %c", "background:#24272A; color:#ffffff", "", "https://blog.xiongtianci.com");
  console.info("%c GitHub %c", "background:#24272A; color:#ffffff", "", "https://github.com/tiancixiong");
  /*End of Initial Variables*/
  </script>
  <script type="text/javascript">
  var bg = "https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/5cm_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/5cm_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_05.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_06.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_07.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_08.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_09.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_10.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_11.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/A.Voyage.of.Chihiro_12.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Atonement_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Atonement_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Atonement_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Atonement_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Avatar_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Before.Sunrise_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Before.Sunrise_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Before.Sunset_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/bighero_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/bighero_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/bighero_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Coco_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Coco_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Coco_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/CUG.King.of.Heroes_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_05.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_06.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_07.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_08.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Digimon_09.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Friends_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Friends_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Friends_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Friends_04.webp,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Friends_05.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Harry.Potter_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Harry.Potter_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Harry.Potter_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Harry.Potter_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Harry.Potter_05.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Hauru.no.ugoku.shiro_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Into.the.Wild_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Kaze.tachinu_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiki_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiki_03.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiki_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiminona_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiminona_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiminona_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiminona_06.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/kiminona_07.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/koenokatachi_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/koenokatachi_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/koenokatachi_03.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Kotonoha.no.Niwa_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/La.La.Land_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Le.Petit.Prince_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Le.Petit.Prince_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mimi.wo.sumaseba_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mr.Bean.Holiday_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mr.Bean.Holiday_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mr.Bean.Holiday_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mr.Bean.Holiday_04.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Mr.Bean.Holiday_05.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/My.Sassy.Girl_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Paperman_01.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Paperman_02.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Piper_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Ponyo_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Ponyo_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Ponyo_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Reply.1988_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Reply.1988_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Reply.1988_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/SpiderMan.Into.the.SpiderVerse_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/SpiderMan.Into.the.SpiderVerse_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/SpiderMan.Into.the.SpiderVerse_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/The.Girl.Who.Leapt.Through.Time_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/The.Pianist_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/TheLonelyAndGreatGod_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Titanic_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Titanic_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Titanic_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/totoro1.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/WALL_E_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/WALL_E_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Zootopia_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/2049.Blade.Runner_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/2049.Blade.Runner_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/American.Dreams.in.China_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Biri.Girl_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Bohemian.Rhapsody_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Bohemian.Rhapsody_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Bohemian.Rhapsody_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Crouching.Tiger.Hidden.Dragon.2000_01.webp,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Detachment_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Detachment_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Gisaengchung_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Iron.Man_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Kureyon.Shinchan_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Love.Actually_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Roman.Holiday_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Roman.Holiday_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Sherlock.S01_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/The.Secret.Life.of.Walter.Mitty_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Youth.Over.Flowers.in.Africa_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Youth.Over.Flowers.in.Africa_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/My.Mister_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/One.Day_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/One.Day_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/One.Day_03.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Ready.Player.One_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Begin.Again_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Begin.Again_02.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/Freddie_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/naruto.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/SetoNaikai_01.jpg,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/yexiu_01.png,https://cdn.jsdelivr.net/gh/tiancixiong/BlogIMG@230521/theme/cover/yexiu_02_FUJISKYTREE.png".split(",");
  var bgindex = Math.floor(Math.random()*bg.length);
  if (!!window.ActiveXObject || "ActiveXObject" in window) { //is IE?
    alert('朋友，IE浏览器未适配哦~');
  }
  </script>
  <style type="text/css">
  .hljs-ln{border-collapse:collapse}.hljs-ln td{padding:0}.hljs-ln-n:before{content:attr(data-line-number)}
  </style>
  <style type="text/css">.site-top .lower nav{display:block !important;}.author-profile i,.post-like a,.post-share .show-share,.sub-text,.we-info a,span.sitename,.post-more i:hover,#pagination a:hover,.post-content a:hover,.float-content i:hover{color:#FE9600}.feature i,.download,.navigator i:hover,.links ul li:before,.ar-time i,span.ar-circle,.object,.comment .comment-reply-link,.siren-checkbox-radio:checked + .siren-checkbox-radioInput:after{background:#FE9600}::-webkit-scrollbar-thumb{background:#FE9600}.download,.navigator i:hover,.link-title,.links ul li:hover,#pagination a:hover,.comment-respond input[type='submit']:hover{border-color:#FE9600}.entry-content a:hover,.site-info a:hover,.comment h4 a,#comments-navi a.prev,#comments-navi a.next,.comment h4 a:hover,.site-top ul li a:hover,.entry-title a:hover,#archives-temp h3,span.page-numbers.current,.sorry li a:hover,.site-title a:hover,i.iconfont.js-toggle-search.iconsearch:hover,.comment-respond input[type='submit']:hover{color:#FE9600}.comments .comments-main{display:block !important;}.comments .comments-hidden{display:none !important;}background-position:center center;background-attachment:inherit;}
  </style>
</head>
</html>
<body class="page-template page-template-user page-template-page-analytics page-template-userpage-analytics-php page page-id-1297 chinese-font serif isWebKit">
  <div class="scrollbar" id="bar">
  </div>
  <a href="#" class="cd-top faa-float animated"></a>
  <section id="main-container">
    <div class="headertop filter-dot">
  <!--首页背景图下方的波浪线-->
  <!--<div id="banner_wave_1"></div>-->
  <!--<div id="banner_wave_2"></div>-->
  <figure id="centerbg" class="centerbg">
    <div class="focusinfo no-select">
      <div class="header-tou">
        <a href="/">
          <img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/avatar.jpg">
        </a>
      </div>
      <div class="header-info">
        <p>You Only Live Once</p>
        <div class="top-social_v2">
          <li id="bg-pre">
            <img class="flipx" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/img/other/next-b.svg">
          </li>
          
            
              
                <li>
                  <a href="https://github.com/tiancixiong" target="_blank" class="social-github" title="github">
                    <img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/social/github.png">
                  </a>
                </li>
              
            
              
                <li>
                  <a href="mailto:support@xiongtianci.com" target="_blank" class="social-github" title="E-mail">
                    <img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/social/email.svg">
                  </a>
                </li>
              
            
          
          <li id="bg-next">
            <img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/img/other/next-b.svg">
          </li>
        </div>
      </div>
    </div>
  </figure>
  <div id="video-container" style="">
    <video style="object-fit: fill" id="bgvideo" class="video" video-name="" src="" width="auto" preload="auto">
    </video>
    <div id="video-btn" class="loadvideo videolive">
    </div>
    <div id="video-add">
    </div>
    <div class="video-stu">
    </div>
  </div>
  <div class="headertop-down faa-float animated" onclick="headertop_down()">
    <span>
      <i class="fa fa-chevron-down" aria-hidden="true">
      </i>
    </span>
  </div>
</div>
    <div id="page" class="site wrapper">
      <header class="site-header no-select gizle sabit" role="banner">
  <div class="site-top">
    <div class="site-branding">
      <span class="site-title">
        <span class="logolink moe-mashiro">
          <a href="/">
            <span class="sakurasono"></span>
            <span class="shironeko">天赐の小站</span>
          </a>
        </span>
      </span>
    </div>
    <div class="searchbox search-form-submit">
      <i class="iconfont js-toggle-search iconsearch icon-search">
      </i>
    </div>
    <div id="show-nav" class="showNav mobile-fit">
      <div class="line line1">
      </div>
      <div class="line line2">
      </div>
      <div class="line line3">
      </div>
    </div>
    <div class="lower-cantiner">
      <div class="lower">
        <nav class="mobile-fit-control hide">
          <ul id="menu-new" class="menu">
            
              <li>
                <a href="/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-fort-awesome faa-horizontal" aria-hidden="true"></i>
                    首页
                  </span>
                </a>
                
              </li>
            
              <li>
                <a href="/archives">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-terminal faa-vertical" aria-hidden="true"></i>
                    极客
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/categories/技术/">
                          <i class="fa fa-code" aria-hidden="true"></i>
                          技术
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/Linux/">
                          <i class="fa fa-linux" aria-hidden="true"></i>
                          Linux
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li>
                <a href="/archives">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-slack faa-spin" aria-hidden="true"></i>
                    爱好
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/categories/电影/">
                          <i class="fa fa-film" aria-hidden="true"></i>
                          电影
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/日语/">
                          <i class="fa fa-language" aria-hidden="true"></i>
                          日语
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li>
                <a href="/archives">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-archive faa-ring" aria-hidden="true"></i>
                    归档
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/categories/生活/">
                          <i class="fa fa-file-text-o" aria-hidden="true"></i>
                          生活
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/随想/">
                          <i class="fa fa-commenting-o" aria-hidden="true"></i>
                          随想
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/资源/">
                          <i class="fa fa-cloud-download" aria-hidden="true"></i>
                          资源
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/转载/">
                          <i class="fa fa-book" aria-hidden="true"></i>
                          转载
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li>
                <a href="/comment/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-pencil-square-o faa-tada" aria-hidden="true"></i>
                    留言板
                  </span>
                </a>
                
              </li>
            
              <li>
                <a href="/links/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-link faa-shake" aria-hidden="true"></i>
                    友人帐
                  </span>
                </a>
                
              </li>
            
              <li>
                <a href="/donate/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-heart faa-burst" aria-hidden="true"></i>
                    赞赏
                  </span>
                </a>
                
              </li>
            
              <li>
                <a href="/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-leaf faa-falling" aria-hidden="true"></i>
                    关于
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/about/">
                          <i class="fa fa-meetup" aria-hidden="true"></i>
                          我？
                        </a>
                      </li>
                    
                      <li>
                        <a href="/theme-sakura/">
                          <i class="fa iconfont icon-sakura" aria-hidden="true"></i>
                          主题
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li>
                <a href="/atom.xml">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-rss faa-passing" aria-hidden="true"></i>
                    RSS
                  </span>
                </a>
                
              </li>
            
          </ul>
        </nav>
      </div>
    </div>
  </div>
</header>

      <link rel="stylesheet" type="text/css" href="/css/sharejs.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css">
<div class="pattern-center-blank"></div>

  <div class="pattern-center single-center">
    <!-- 有配图默认渲染第一张 -->
    <div class="pattern-attachment-img lazyload" style="background-image: url(https://images.unsplash.com/photo-1528164344705-47542687000d?w=540);" src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/loader/orange.progress-bar-stripe-loader.svg" data-src="https://images.unsplash.com/photo-1528164344705-47542687000d?w=540">
    </div>
    <header class="pattern-header single-header">
      <h1 class="entry-title">
      JUC学习笔记-显式锁：ReentrantLock详解</h1>
      <p class="entry-census">
        <span>
          <a href="https://blog.xiongtianci.com">
            <img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/avatar.jpg">
          </a>
        </span>
        <span>
          <a href="https://blog.xiongtianci.com">木浅</a>
        </span>
        <span class="bull">
        ·</span>
        2024-4-3<span class="bull">
        ·</span>
      <span id="busuanzi_value_page_pv"></span>次阅读</p>
    </header>
  </div>

<div id="content" class="site-content">
  <div id="primary" class="content-area">
    <main id="main" class="site-main" role="main">
      <article id="post-1" class="post-1 post type-post status-publish format-standard has-post-thumbnail hentry category-uncategorized">
        <div class="toc"></div>
        <!--<div class="toc-entry-content"><!-- 套嵌目录使用（主要为了支援评论）-->
        
        <div class="entry-content">
          <h1 id="ReentrantLock"><a href="#ReentrantLock" class="headerlink" title="ReentrantLock"></a>ReentrantLock</h1><p><code>ReentrantLock</code> 是 Java 并发工具包 (<code>java.util.concurrent.locks</code>) 中的一个重要类，它实现了 <code>Lock</code> 接口，提供了比 <code>synchronized</code> 更灵活、更强大的锁机制。</p>
<p>与synchronized的对比</p>
<table>
<thead>
<tr>
<th style="text-align:left">特性</th>
<th style="text-align:left">ReentrantLock</th>
<th style="text-align:left">synchronized</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">实现机制</td>
<td style="text-align:left">JDK层面实现</td>
<td style="text-align:left">JVM层面实现</td>
</tr>
<tr>
<td style="text-align:left">锁获取方式</td>
<td style="text-align:left">显式lock()/unlock()</td>
<td style="text-align:left">隐式获取和释放</td>
</tr>
<tr>
<td style="text-align:left">可中断性</td>
<td style="text-align:left">支持lockInterruptibly()</td>
<td style="text-align:left">不支持</td>
</tr>
<tr>
<td style="text-align:left">公平性</td>
<td style="text-align:left">可配置公平/非公平模式</td>
<td style="text-align:left">完全非公平</td>
</tr>
<tr>
<td style="text-align:left">条件变量</td>
<td style="text-align:left">支持多个Condition</td>
<td style="text-align:left">单个等待队列</td>
</tr>
<tr>
<td style="text-align:left">性能</td>
<td style="text-align:left">高竞争下表现更好</td>
<td style="text-align:left">Java 6后优化相当</td>
</tr>
<tr>
<td style="text-align:left">锁绑定</td>
<td style="text-align:left">一个锁可绑定多个条件队列</td>
<td style="text-align:left">锁与条件队列一对一绑定</td>
</tr>
</tbody>
</table>
<p>核心方法：</p>
<pre><code class="java">public class ReentrantLock implements Lock {
    // 获取锁（不可中断）
    public void lock();

    // 尝试获取锁（立即返回）
    public boolean tryLock();

    // 尝试获取锁（带超时）
    public boolean tryLock(long timeout, TimeUnit unit);

    // 获取锁（可中断）
    public void lockInterruptibly();

    // 释放锁
    public void unlock();

    // 创建条件变量
    public Condition newCondition();
}
</code></pre>
<h1 id="基础使用"><a href="#基础使用" class="headerlink" title="基础使用"></a>基础使用</h1><p>1、<strong>锁的获取和释放必须成对出现</strong>：</p>
<pre><code class="java">ReentrantLock lock = new ReentrantLock();

lock.lock();  // 必须在try块外获取锁
try {
    // 临界区代码
} finally {
    lock.unlock();  // 确保锁释放
}
</code></pre>
<ul>
<li><p>锁的获取（<code>lock()</code>） 必须在 <code>try</code> 外。如果在 <code>try</code> 内加锁，可能锁未成功但 <code>finally</code> 仍会执行 <code>unlock()</code>。</p>
<p><strong>对比 <code>synchronized</code></strong>：<code>synchronized</code> 是 Java 内置锁，无需手动释放，因此不会存在此问题：</p>
<pre><code class="java">synchronized (lockObject) {  // 自动加锁/解锁
    // 临界区代码
}
</code></pre>
</li>
</ul>
<p>  但 <code>ReentrantLock</code> 是显式锁，必须严格遵循 <code>lock-unlock</code> 的配对规则</p>
<p>2、<strong>可中断的加锁</strong>（避免死锁）：</p>
<pre><code class="java">if (lock.tryLock(1, TimeUnit.SECONDS)) { // 尝试获取锁，超时放弃
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }
} else {
    // 处理加锁失败
}
</code></pre>
<h1 id="场景案例"><a href="#场景案例" class="headerlink" title="场景案例"></a>场景案例</h1><h2 id="lock-的使用"><a href="#lock-的使用" class="headerlink" title="lock()的使用"></a><code>lock()</code>的使用</h2><p><strong>账户转账案例</strong>：</p>
<pre><code class="java">public class BankAccount {
    private final ReentrantLock lock = new ReentrantLock();
    private int balance;

    public void transfer(BankAccount to, int amount) {
        // 解决死锁：按hash排序获取锁
        BankAccount first = this.hashCode() &lt; to.hashCode() ? this : to;
        BankAccount second = first == this ? to : this;

        // 按顺序加锁
        first.lock.lock(); // 先锁第一个账户
        try {
            second.lock.lock(); // 再锁第二个账户
            try {
                // 检查余额并转账
                if (this.balance &gt;= amount) {
                    this.balance -= amount;
                    to.balance += amount;
                }
            } finally {
                second.lock.unlock(); // 释放第二个锁
            }
        } finally {
            first.lock.unlock(); // 释放第一个锁
        }
    }
}
</code></pre>
<ul>
<li><p>通过 <strong>锁排序（Lock Ordering）</strong> 避免死锁：按对象的哈希值排序，决定加锁顺序，所有线程都按 <code>first → second</code> 的顺序加锁，避免循环等待</p>
<p>如果 <code>hashCode</code> 相同，仍然可能死锁（但概率极低），可以用 <code>System.identityHashCode()</code> 替代：</p>
<pre><code class="java">BankAccount first = System.identityHashCode(this) &lt; System.identityHashCode(to) ? this : to;
</code></pre>
</li>
<li><p>如果账户可能动态变化，可以用 <code>UUID</code> 或数据库 ID 排序：</p>
<pre><code class="java">BankAccount first = this.getId().compareTo(to.getId()) &lt; 0 ? this : to;
</code></pre>
</li>
</ul>
<p><code>System.identityHashCode</code> 和 <code>hashCode</code> 比较：</p>
<table>
<thead>
<tr>
<th style="text-align:left"><strong>对比项</strong></th>
<th style="text-align:left"><code>hashCode()</code></th>
<th style="text-align:left"><code>System.identityHashCode()</code></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>是否可重写</strong></td>
<td style="text-align:left">是（可能人为导致冲突）</td>
<td style="text-align:left">否（始终返回 JVM 内部标识）</td>
</tr>
<tr>
<td style="text-align:left"><strong>冲突概率</strong></td>
<td style="text-align:left">高（如 <code>String</code> 哈希算法可能碰撞）</td>
<td style="text-align:left">极低（依赖对象内存地址）</td>
</tr>
<tr>
<td style="text-align:left"><strong>适用场景</strong></td>
<td style="text-align:left">需要语义相等的对象（如 <code>HashMap</code>）</td>
<td style="text-align:left">需要唯一对象标识（如锁排序、调试）</td>
</tr>
</tbody>
</table>
<h2 id="lockInterruptibly"><a href="#lockInterruptibly" class="headerlink" title="lockInterruptibly()"></a><code>lockInterruptibly()</code></h2><p><strong>可中断锁</strong>（死锁处理）</p>
<pre><code class="java">import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptibleLockDemo {
    private final ReentrantLock lock1 = new ReentrantLock();
    private final ReentrantLock lock2 = new ReentrantLock();

    public void threadA() {
        try {
            lock1.lockInterruptibly(); // 可中断获取锁1
            try {
                Thread.sleep(100); // 模拟工作耗时
                lock2.lockInterruptibly(); // 可中断获取锁2
                try {
                    System.out.println(&quot;ThreadA完成任务&quot;);
                } finally {
                    lock2.unlock(); // 释放锁2
                }
            } finally {
                lock1.unlock(); // 释放锁1
            }
        } catch (InterruptedException e) {
            System.out.println(&quot;ThreadA被中断&quot;); // 响应中断
        }
    }

    // threadB和threadA类似但以相反顺序获取锁
    public void threadB() {
        try {
            lock2.lockInterruptibly();  // 先获取锁2
            try {
                Thread.sleep(100);      // 模拟工作耗时
                lock1.lockInterruptibly(); // 再尝试获取锁1
                try {
                    System.out.println(&quot;ThreadB完成任务&quot;);
                } finally {
                    lock1.unlock();
                }
            } finally {
                lock2.unlock();
            }
        } catch (InterruptedException e) {
            System.out.println(&quot;ThreadB被中断&quot;);
        }
    }

    public static void main(String[] args) {
        InterruptibleLockDemo demo = new InterruptibleLockDemo();
        Thread t1 = new Thread(demo::threadA);
        Thread t2 = new Thread(demo::threadB);

        // threadA 先获取 lock1，再尝试获取 lock2
        // threadB 先获取 lock2，再尝试获取 lock1
        // 两个线程同时执行，会互相等待对方的锁，导致死锁
        t1.start();
        t2.start();

        // 中断死锁
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                t1.interrupt(); // 中断线程1
                t2.interrupt(); // 中断线程2
                timer.cancel(); // 关闭定时器
            }
        }, 2000); // 2秒后中断线程
    }
}
</code></pre>
<ul>
<li><code>lockInterruptibly()</code>：如果线程在等待锁时被中断，会立即抛出 <code>InterruptedException</code></li>
<li><code>Timer</code> 在 <strong>2秒后</strong> 触发，<strong>无条件中断</strong> 这两个线程（无论是否真的死锁）。线程被中断后，<code>lockInterruptibly()</code> 会抛出 <code>InterruptedException</code>，释放已持有的锁，从而解除死锁<ul>
<li>调用 <code>timer.cancel()</code> 停止 <code>Timer</code>，避免重复中断</li>
</ul>
</li>
</ul>
<p><strong>为什么用 <code>lockInterruptibly()</code>？</strong></p>
<ul>
<li><strong>避免永久阻塞</strong>：普通 <code>lock()</code> 会无视中断请求，导致线程无法退出；<code>lockInterruptibly()</code> 如果线程在等待锁时被中断，会立即抛出 <code>InterruptedException</code></li>
<li><strong>适合需要响应中断的场景</strong>：如任务超时、系统关闭等。</li>
</ul>
<h2 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h2><p><strong>公平锁</strong>（订单处理系统）</p>
<pre><code class="java">import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;

// 订单处理系统，使用公平锁来保证多线程环境下的订单处理顺序
public class OrderProcessingSystem {
    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁

    public void processOrder(Order order) {
        System.out.println(Thread.currentThread().getName() +
                &quot; 尝试获取锁，时间: &quot; + System.currentTimeMillis());
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()
                    + &quot; 处理订单: &quot; + order.getId());
            // 模拟处理时间
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            System.out.println(Thread.currentThread().getName() + &quot; 被中断，取消订单处理&quot;);
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        OrderProcessingSystem system = new OrderProcessingSystem();
        CountDownLatch lockHeldSignal = new CountDownLatch(1); // 信号量：锁已被占用

        // 先启动一个线程，长时间持有锁
        new Thread(() -&gt; {
            system.lock.lock(); // 直接占锁，不执行订单
            System.out.println(&quot;Blocking-Thread 已持有锁，迫使其他线程排队&quot;);
            lockHeldSignal.countDown(); // 通知主线程：锁已被占用
            try {
                Thread.sleep(2000); // 模拟长时间持有锁
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                system.lock.unlock();
            }
        }, &quot;Blocking-Thread&quot;).start();

        // 确保锁已被占用后再启动其他线程
        try {
            lockHeldSignal.await(); // 阻塞，直到锁被占用
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 此时锁已被占用，公平锁会按顺序分配
        ExecutorService executor = Executors.newFixedThreadPool(10);
        IntStream.range(0, 10).forEach(i -&gt; {
            executor.submit(() -&gt; {
                system.processOrder(new Order(i));
            });
        });
        executor.shutdown();
    }
}

class Order {
    private final int id;
    public Order(int id) {
        this.id = id;
    }
    public int getId() {
        return id;
    }
}
</code></pre>
<p><strong><code>ReentrantLock(true)</code></strong></p>
<ul>
<li>使用 <strong>公平锁</strong>（<code>fair=true</code>），确保线程按请求锁的顺序获取锁（避免线程饥饿）。</li>
<li>如果是非公平锁（默认），线程可能会插队，导致某些线程长时间等待。</li>
</ul>
<h2 id="ReentrantLock-Condition"><a href="#ReentrantLock-Condition" class="headerlink" title="ReentrantLock + Condition"></a>ReentrantLock + Condition</h2><h3 id="生产者消费者模式"><a href="#生产者消费者模式" class="headerlink" title="生产者消费者模式"></a>生产者消费者模式</h3><pre><code class="java">import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MessageQueue&lt;T&gt; {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition(); // 队列未满条件
    private final Condition notEmpty = lock.newCondition(); // 队列非空条件
    private final Object[] items; // 环形队列
    private int putPtr, takePtr, count; // 写入指针、读取指针、当前元素数

    public MessageQueue(int capacity) {
        items = new Object[capacity];
    }

    public void put(T x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length) {
                notFull.await();  // 队列满时等待
            }
            items[putPtr] = x; // 写入数据
            if (++putPtr == items.length) putPtr = 0; // 环形指针处理
            count++;
            notEmpty.signal();  // 唤醒一个消费者线程
        } finally {
            lock.unlock();
        }
    }

    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) { // 队列空时等待
                notEmpty.await();  // 释放锁并阻塞
            }
            @SuppressWarnings(&quot;unchecked&quot;)
            T x = (T) items[takePtr]; // 读取数据
            if (++takePtr == items.length) takePtr = 0; // 环形指针处理
            count--;
            notFull.signal();  // 唤醒一个生产者线程
            return x;
        } finally {
            lock.unlock();
        }
    }
}
class MessageQueueTest {
    public static void main(String[] args) throws InterruptedException {
        MessageQueue&lt;String&gt; queue = new MessageQueue&lt;&gt;(5);  // 容量为5的队列

        // 生产者线程
        ExecutorService producer = Executors.newSingleThreadExecutor();
        producer.submit(() -&gt; {
            try {
                for (int i = 0; i &lt; 10; i++) {
                    queue.put(&quot;消息-&quot; + i);
                    System.out.println(&quot;生产: 消息-&quot; + i);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 消费者线程
        ExecutorService consumer = Executors.newSingleThreadExecutor();
        consumer.submit(() -&gt; {
            try {
                for (int i = 0; i &lt; 10; i++) {
                    String msg = queue.take();
                    System.out.println(&quot;消费: &quot; + msg);
                    Thread.sleep(200);  // 模拟处理耗时
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        producer.shutdown();
        consumer.shutdown();
        producer.awaitTermination(10, TimeUnit.SECONDS);
        consumer.awaitTermination(10, TimeUnit.SECONDS);
    }
}
</code></pre>
<ol>
<li><p>ReentrantLock互斥访问共享资源</p>
<ul>
<li><p><strong>保护共享变量</strong>：<code>items</code>（队列数组）、<code>putPtr</code>（写入指针）、<code>takePtr</code>（读取指针）、<code>count</code>（当前元素数量）的读写操作必须互斥。</p>
</li>
<li><p>保证 <code>put</code> 和 <code>take</code> 操作的原子性，防止并发修改导致数据不一致。</p>
</li>
</ul>
</li>
<li><p>条件变量（<code>Condition</code>）实现精准唤醒</p>
<ul>
<li><p><strong><code>notFull</code></strong>：队列未满时唤醒生产者线程（<code>put</code> 方法）。</p>
</li>
<li><p><strong><code>notEmpty</code></strong>：队列非空时唤醒消费者线程（<code>take</code> 方法）。</p>
</li>
<li><p>避免虚假唤醒：通过 <code>while</code> 循环重复检查条件（如 <code>while (count == 0)</code>）。</p>
</li>
</ul>
</li>
<li><p>阻塞操作：</p>
<ul>
<li>队列满时，<code>put</code> 方法阻塞生产者，直到有空位。</li>
<li>队列空时，<code>take</code> 方法阻塞消费者，直到有新数据。</li>
</ul>
</li>
</ol>
<h4 id="完整工作流程"><a href="#完整工作流程" class="headerlink" title="完整工作流程"></a>完整工作流程</h4><p>生产者线程（put）</p>
<pre><code class="mermaid">sequenceDiagram
    participant Producer
    participant Lock
    participant notFull
    participant Queue

    Producer-&gt;&gt;Lock: lock()
    alt 队列已满
        Producer-&gt;&gt;notFull: await()
        notFull--&gt;&gt;Producer: 阻塞并释放锁
    else 队列未满
        Producer-&gt;&gt;Queue: 写入数据
        Producer-&gt;&gt;notEmpty: signal()
    end
    Producer-&gt;&gt;Lock: unlock()
</code></pre>
<p>消费者线程（take）</p>
<pre><code class="mermaid">sequenceDiagram
    participant Consumer
    participant Lock
    participant notEmpty
    participant Queue

    Consumer-&gt;&gt;Lock: lock()
    alt 队列为空
        Consumer-&gt;&gt;notEmpty: await()
        notEmpty--&gt;&gt;Consumer: 阻塞并释放锁
    else 队列非空
        Consumer-&gt;&gt;Queue: 读取数据
        Consumer-&gt;&gt;notFull: signal()
    end
    Consumer-&gt;&gt;Lock: unlock()
</code></pre>
<h3 id="线程交替执行"><a href="#线程交替执行" class="headerlink" title="线程交替执行"></a>线程交替执行</h3><p><strong>银行叫号系统</strong></p>
<pre><code class="java">import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 银行票务系统，通过 ReentrantLock 和 Condition 实现 VIP客户优先 的业务办理逻辑：
 *  - VIP客户：优先办理，处理完成后切换回普通模式。
 *  - 普通客户：按顺序办理，每处理3个后切换VIP模式。
 */
public class BankTicketSystem {
    private final ReentrantLock lock = new ReentrantLock();
    // VIP客户的等待队列（当 isVipTurn=false 时阻塞）
    private final Condition vipCondition = lock.newCondition();
    // 普通客户的等待队列（当 isVipTurn=true 时阻塞）
    private final Condition normalCondition = lock.newCondition();
    // 当前是否优先处理VIP客户
    private boolean isVipTurn = false;

    // VIP客户流程
    public void vipCustomer(int num) throws InterruptedException {
        lock.lock();
        try {
            while (!isVipTurn) { // 如果不是VIP轮次，释放锁并阻塞
                vipCondition.await();
            }
            System.out.println(&quot;VIP客户-&quot; + num + &quot;正在办理业务&quot;);
            Thread.sleep(500); // 模拟业务处理
            isVipTurn = false; // 切换为普通模式
            normalCondition.signalAll(); // 唤醒所有普通客户
        } finally {
            lock.unlock();
        }
    }

    // 普通客户流程
    public void normalCustomer(int num) throws InterruptedException {
        lock.lock();
        try {
            while (isVipTurn) {
                normalCondition.await();
            }
            System.out.println(&quot;普通客户-&quot; + num + &quot;正在办理业务&quot;);
            Thread.sleep(300); // 模拟业务处理
            if (num % 3 == 0) { // 每处理3个普通客户切换VIP
                isVipTurn = true;
                vipCondition.signal(); // 唤醒一个VIP客户
            }
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        BankTicketSystem system = new BankTicketSystem();

        // VIP客户线程（每隔一段时间尝试办理）
        new Thread(() -&gt; {
            for (int i = 1; i &lt;= 5; i++) {
                try {
                    system.vipCustomer(i);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();

        // 普通客户线程（持续办理）
        new Thread(() -&gt; {
            for (int i = 1; i &lt;= 10; i++) {
                try {
                    system.normalCustomer(i);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }
}
</code></pre>
<ul>
<li><code>signal()</code> vs <code>signalAll()</code>：VIP客户唤醒一个即可，普通客户需唤醒所有（避免遗漏）</li>
</ul>
<p>大致流程：</p>
<pre><code>普通客户-1 办理
普通客户-2 办理
普通客户-3 办理 → 切换VIP模式
VIP客户-1 办理 → 切换普通模式
普通客户-4 办理
...
</code></pre><h3 id="交易系统订单匹配引擎"><a href="#交易系统订单匹配引擎" class="headerlink" title="交易系统订单匹配引擎"></a>交易系统订单匹配引擎</h3><pre><code class="java">/**
 * 订单撮合引擎 的简化实现，用于模拟金融市场中的买卖订单匹配逻辑。
 * 核心功能包括：
 * - 订单管理：按价格优先级维护买卖订单队列。
 * - 撮合引擎：持续匹配符合价格的买卖订单。
 * - 线程安全：通过 ReentrantLock 和 Condition 保证并发安全。
 */
public class OrderMatchingEngine {
    private final ReentrantLock lock = new ReentrantLock();
    // 通知机制，当新订单到达时唤醒撮合线程
    private final Condition orderAdded = lock.newCondition();
    // 买方订单队列，按价格 降序 排列（高价优先）
    private final PriorityQueue&lt;Order&gt; buyOrders = new PriorityQueue&lt;&gt;(
            (a, b) -&gt; Double.compare(b.getPrice(), a.getPrice()));
    // 卖方订单队列，按价格 升序 排列（低价优先）
    private final PriorityQueue&lt;Order&gt; sellOrders = new PriorityQueue&lt;&gt;(
            Comparator.comparingDouble(Order::getPrice));

    // 添加订单
    public void addOrder(Order order) {
        lock.lock();
        try {
            if (order.getType() == OrderType.BUY) {
                buyOrders.add(order);
            } else {
                sellOrders.add(order);
            }
            orderAdded.signalAll(); // 唤醒撮合线程
        } finally {
            lock.unlock();
        }
    }

    // 订单撮合逻辑
    public void matchOrders() throws InterruptedException {
        lock.lock();
        try {
            while (true) {
                // 检查是否可撮合
                // 如果买方或卖方队列为空，或最高买价 &lt; 最低卖价 则无法成交
                while (buyOrders.isEmpty() || sellOrders.isEmpty()
                        || buyOrders.peek().getPrice() &lt; sellOrders.peek().getPrice()) {
                    orderAdded.await(); // 阻塞等待新订单
                }

                // 执行撮合
                // 取出队列头部订单（最高买价和最低卖价）成交，计算成交价（买卖均价的中间价）和成交量（较小数量）
                Order buy = buyOrders.poll();
                Order sell = sellOrders.poll();
                double price = (buy.getPrice() + sell.getPrice()) / 2; // 中间价成交
                // 取买卖双方数量的较小值，确保成交不超过任一方意愿
                double quantity = Math.min(buy.getQuantity(), sell.getQuantity());

                System.out.printf(&quot;成交: %.2f @ %.2f%n&quot;, quantity, price);

                // 处理剩余数量
                if (buy.getQuantity() &gt; quantity) {
                    buy.setQuantity(buy.getQuantity() - quantity);
                    buyOrders.add(buy); // 放回剩余部分
                }
                if (sell.getQuantity() &gt; quantity) {
                    sell.setQuantity(sell.getQuantity() - quantity);
                    sellOrders.add(sell);
                }
            }
        } finally {
            lock.unlock();
        }
    }
}
class Order {
    private final OrderType type; // BUY 或 SELL
    private final double price;
    private double quantity; // 股票数量

    // Constructor, Getters, Setters...
}

enum OrderType { BUY, SELL }
</code></pre>
<ul>
<li><code>PriorityQueue&lt;Order&gt;</code> 优先队列，按价格排序，分别存储买方和卖方的未成交订单，确保高效撮合</li>
</ul>
<p>阻塞唤醒机制</p>
<ul>
<li><strong>等待条件</strong>：当无法撮合时，调用 <code>orderAdded.await()</code> 释放锁并阻塞。</li>
<li><strong>唤醒条件</strong>：<code>addOrder</code> 添加新订单后调用 <code>orderAdded.signalAll()</code>。</li>
</ul>
<h2 id="锁分段技术"><a href="#锁分段技术" class="headerlink" title="锁分段技术"></a>锁分段技术</h2><p>库存系统</p>
<pre><code class="java">import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

// 分段锁（Striped Lock） 实现线程安全库存系统
// 通过 数据分片 减少锁竞争，提高并发性能
public class SegmentInventory {
    // 每个段包含的item数量（向上取整）
    private final int segmentSize;
    // 锁数组，每个段一个独立锁
    private final ReentrantLock[] locks;
    // 库存数据数组，counts[itemId] 表示对应商品的库存数
    private final int[] counts;

    /**
     * @param itemCount        商品总数
     * @param concurrencyLevel 并发段数
     */
    public SegmentInventory(int itemCount, int concurrencyLevel) {
        // 计算每个段的大小
        this.segmentSize = (itemCount + concurrencyLevel - 1) / concurrencyLevel;
        this.locks = new ReentrantLock[concurrencyLevel];
        this.counts = new int[itemCount];
        Arrays.setAll(locks, i -&gt; new ReentrantLock()); // 初始化锁数组
    }

    // 增加库存
    public void increase(int itemId) {
        int segment = itemId / segmentSize; // 计算所属段
        locks[segment].lock(); // 获取分段锁
        try {
            counts[itemId]++; // 修改库存
        } finally {
            locks[segment].unlock(); // 释放锁
        }
    }

    // 查询库存
    public int getCount(int itemId) {
        int segment = itemId / segmentSize;
        locks[segment].lock();
        try {
            return counts[itemId]; // 返回库存
        } finally {
            locks[segment].unlock();
        }
    }
}
class SegmentInventoryTest {
    public static void main(String[] args) throws InterruptedException {
        // 分段锁性能验证。分段锁性能优于全局锁
//        testPerformance();
        // 分段冲突测试。同段操作串行，不同段并发
        testSegmentConflict();
    }

    static void testPerformance() throws InterruptedException {
        int itemCount = 1000;
        int threads = 16;

        // 测试全局锁性能
        long start1 = System.currentTimeMillis();
        testWithGlobalLock(itemCount, threads);
        long duration1 = System.currentTimeMillis() - start1;

        // 测试分段锁性能
        long start2 = System.currentTimeMillis();
        testWithSegmentLock(itemCount, threads);
        long duration2 = System.currentTimeMillis() - start2;

        System.out.println(&quot;全局锁耗时: &quot; + duration1 + &quot;ms&quot;);
        System.out.println(&quot;分段锁耗时: &quot; + duration2 + &quot;ms&quot;);
    }
    static void testWithGlobalLock(int itemCount, int threads) throws InterruptedException {
        ReentrantLock globalLock = new ReentrantLock();
        int[] counts = new int[itemCount];
        ExecutorService executor = Executors.newFixedThreadPool(threads);

        for (int i = 0; i &lt; 10000; i++) {
            int itemId = i % itemCount;
            executor.submit(() -&gt; {
                globalLock.lock();
                try {
                    counts[itemId]++;
                } finally {
                    globalLock.unlock();
                }
            });
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
    }

    static void testWithSegmentLock(int itemCount, int threads) throws InterruptedException {
        SegmentInventory inventory = new SegmentInventory(itemCount, 16); // 16个分段
        ExecutorService executor = Executors.newFixedThreadPool(threads);

        for (int i = 0; i &lt; 10000; i++) {
            int itemId = i % itemCount;
            executor.submit(() -&gt; inventory.increase(itemId));
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);
    }

    static void testSegmentConflict() throws InterruptedException {
        SegmentInventory inventory = new SegmentInventory(100, 4); // 段大小=25
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 两个线程操作同段的item（26和30属于段1）
        executor.submit(() -&gt; {
            for (int i = 0; i &lt; 1000; i++) inventory.increase(26);
        });
        executor.submit(() -&gt; {
            for (int i = 0; i &lt; 1000; i++) inventory.increase(30);
        });

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.SECONDS);
        System.out.println(&quot;商品26库存: &quot; + inventory.getCount(26)); // 预期1000
        System.out.println(&quot;商品30库存: &quot; + inventory.getCount(30)); // 预期1000
    }
}
</code></pre>
<ul>
<li>操作 <code>itemId=5</code> 和 <code>itemId=30</code> 会分别锁定 <strong>段0</strong> 和 <strong>段1</strong>，互不阻塞。</li>
<li>操作 <code>itemId=10</code> 和 <code>itemId=20</code> 均属于 <strong>段0</strong>，会互斥阻塞。</li>
</ul>
<ol>
<li><p>segmentSize 计算公式：<code>segmentSize = (itemCount + concurrencyLevel - 1) / concurrencyLevel;</code>，通过 <code>(itemCount + concurrencyLevel - 1)</code> 调整分子，确保所有库存项被覆盖：</p>
<ul>
<li>当 <code>itemCount</code> 不能被 <code>concurrencyLevel</code> 整除时，余数部分会使得分子足够大，从而让整数除法结果增加 <code>1</code>。</li>
<li>如果整除，则 <code>+ concurrencyLevel - 1</code> 不会改变结果。</li>
</ul>
</li>
<li><p>分段映射规则：<code>int segment = itemId / segmentSize;</code></p>
<p><strong>为什么分段映射用除法（<code>/</code>）而不是取模（<code>%</code>）？</strong></p>
<ul>
<li><p>使用除法的目的：将连续的 <code>itemId</code> 分配到同一个分段，保证 <strong>局部性</strong>（Locality），减少锁切换开销。</p>
</li>
<li><p>用取模会破坏局部性，取模会导致相邻的 <code>itemId</code> 被分散到不同分段，增加锁竞争概率。</p>
</li>
<li><p>除法 vs 取模的对比</p>
<p>| <strong>操作</strong> | <strong>效果</strong>                       | <strong>适用场景</strong>                             |<br>| :——- | :—————————– | :————————————— |<br>| <code>/</code>      | 按范围分片（连续ID归到同一段） | 需要局部性优化的场景（如相邻ID高频访问） |<br>| <code>%</code>      | 哈希分片（ID均匀分散到各段）   | 需要绝对均匀分布的场景                   |</p>
</li>
</ul>
</li>
</ol>
<p>与全局锁比较：</p>
<table>
<thead>
<tr>
<th style="text-align:left"><strong>场景</strong></th>
<th style="text-align:left"><strong>全局锁（synchronized）</strong></th>
<th style="text-align:left"><strong>分段锁（SegmentInventory）</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">操作不同段的item</td>
<td style="text-align:left">串行执行</td>
<td style="text-align:left">并行执行（无竞争）</td>
</tr>
<tr>
<td style="text-align:left">操作同段的item</td>
<td style="text-align:left">串行执行</td>
<td style="text-align:left">串行执行（段内竞争）</td>
</tr>
<tr>
<td style="text-align:left">锁竞争概率</td>
<td style="text-align:left">高</td>
<td style="text-align:left">低（与 <code>concurrencyLevel</code> 相关）</td>
</tr>
<tr>
<td style="text-align:left">适用场景</td>
<td style="text-align:left">低并发</td>
<td style="text-align:left">高并发（如电商库存系统）</td>
</tr>
</tbody>
</table>
<h2 id="锁降级"><a href="#锁降级" class="headerlink" title="锁降级"></a>锁降级</h2><p><strong>缓存系统</strong></p>
<pre><code class="java">import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

// 基于 读写锁（ReentrantReadWriteLock） 的线程安全缓存系统
public class CacheSystem&lt;K, V&gt; {
    // 提供读写锁分离机制
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock readLock = rwl.readLock(); // 共享锁，允许多线程并发读
    private final Lock writeLock = rwl.writeLock(); // 独占锁，写操作或缓存更新时使用
    private Map&lt;K, V&gt; cache = new HashMap&lt;&gt;();

    public V get(K key) {
        // 第一阶段：尝试读缓存（共享锁）
        readLock.lock();
        try {
            V value = cache.get(key);
            if (value != null) {
                return value; // 缓存命中直接返回
            }
        } finally {
            readLock.unlock();
        }

        // 第二阶段：缓存未命中，加写锁
        writeLock.lock();
        try {
            // 双重检查，防止其他线程已更新
            V value = cache.get(key);
            if (value == null) {
                value = loadFromDatabase(key); // 模拟数据库加载
                cache.put(key, value);
            }
            // 锁降级：在释放写锁前获取读锁
            readLock.lock();
            return value;
        } finally {
            writeLock.unlock(); // 释放写锁，保持读锁
            // 此处仍持有读锁，保护后续操作
        }
    }

    private V loadFromDatabase(K key) {
        // 模拟数据库加载
        return null;
    }
}
</code></pre>
<p>关键点：</p>
<ol>
<li><p>双重检查的必要性</p>
<pre><code class="java">writeLock.lock();
try {
    // 再次检查缓存
    V value = cache.get(key);
    if (value == null) {
        value = loadFromDatabase(key);
        cache.put(key, value);
    }
    // ...
}
</code></pre>
<ul>
<li><strong>目的</strong>：防止多个线程同时通过第一次检查后，重复加载数据（缓存击穿）。</li>
<li><strong>效果</strong>：只有第一个拿到写锁的线程会执行加载，后续线程直接读取缓存。</li>
</ul>
</li>
<li><p>锁降级（Lock Downgrading）</p>
<pre><code class="java">writeLock.lock();
try {
    // ... 写操作
    readLock.lock();  // 锁降级
} finally {
    writeLock.unlock(); // 释放写锁，保持读锁
}
</code></pre>
<ul>
<li><p>作用：</p>
<ul>
<li><p>保证在写锁释放后，其他线程无法修改数据（因为仍持有读锁）。</p>
</li>
<li><p>避免数据在返回过程中被其他写操作破坏一致性。</p>
</li>
</ul>
</li>
<li><p>注意事项：</p>
<ul>
<li>锁降级 <strong>必须</strong> 在写锁未释放前获取读锁，顺序不能颠倒。</li>
<li>不支持锁升级（读锁 → 写锁），会导致死锁。</li>
</ul>
</li>
</ul>
</li>
</ol>
<hr>
<p>Q：<strong>锁降级是否必要？</strong></p>
<p>如果去掉锁降级：</p>
<pre><code class="java">writeLock.lock();
try {
    V value = cache.get(key);
    if (value == null) {
        value = loadFromDatabase(key);
        cache.put(key, value);
    }
    return value; // 直接返回，不持有读锁
} finally {
    writeLock.unlock();
}
</code></pre>
<p>在 <code>writeLock.unlock()</code> 和返回结果之间，其他线程可能修改数据，导致返回脏数据。</p>
<h2 id="分布式锁（基于Redis-ReentrantLock）"><a href="#分布式锁（基于Redis-ReentrantLock）" class="headerlink" title="分布式锁（基于Redis+ReentrantLock）"></a>分布式锁（基于Redis+ReentrantLock）</h2><pre><code class="java">public class DistributedLock {
    private final ReentrantLock localLock = new ReentrantLock();
    private final RedisTemplate&lt;String, String&gt; redisTemplate;
    private final String lockKey;
    private final String clientId = UUID.randomUUID().toString();
    private final long expireTime = 30000; // 30秒

    public boolean tryLock(long waitTime) throws InterruptedException {
        long start = System.currentTimeMillis();

        // 先获取本地锁
        if (!localLock.tryLock(waitTime, TimeUnit.MILLISECONDS)) {
            return false;
        }

        try {
            // 循环尝试获取分布式锁
            do {
                Boolean success = redisTemplate.opsForValue().setIfAbsent(
                    lockKey, clientId, expireTime, TimeUnit.MILLISECONDS);
                if (Boolean.TRUE.equals(success)) {
                    return true;
                }

                // 检查锁是否过期
                String currentValue = redisTemplate.opsForValue().get(lockKey);
                if (currentValue != null &amp;&amp; Long.parseLong(currentValue) &lt; System.currentTimeMillis()) {
                    // 锁已过期，尝试抢占
                    String oldValue = redisTemplate.opsForValue().getAndSet(
                        lockKey, clientId);
                    if (oldValue != null &amp;&amp; oldValue.equals(currentValue)) {
                        return true;
                    }
                }

                if (System.currentTimeMillis() - start &gt; waitTime) {
                    break;
                }

                Thread.sleep(100); // 短暂等待后重试
            } while (true);

            return false;
        } finally {
            localLock.unlock();
        }
    }

    public void unlock() {
        // 先检查本地锁
        if (!localLock.isHeldByCurrentThread()) {
            throw new IllegalMonitorStateException();
        }

        try {
            // 验证是当前客户端持有的锁
            String value = redisTemplate.opsForValue().get(lockKey);
            if (clientId.equals(value)) {
                redisTemplate.delete(lockKey);
            }
        } finally {
            localLock.unlock();
        }
    }
}
</code></pre>
<h1 id="常见问题与解决方案"><a href="#常见问题与解决方案" class="headerlink" title="常见问题与解决方案"></a>常见问题与解决方案</h1><h2 id="死锁预防"><a href="#死锁预防" class="headerlink" title="死锁预防"></a>死锁预防</h2><p><strong>问题代码</strong>：</p>
<pre><code class="java">// 线程1
lockA.lock();
lockB.lock();

// 线程2
lockB.lock();
lockA.lock();
</code></pre>
<p><strong>解决方案</strong></p>
<p>方案一 <strong>锁顺序一致性</strong></p>
<ul>
<li>确保所有线程以相同的顺序获取多个锁：先 <code>from</code> 后 <code>to</code>，避免死锁（需全局统一顺序）</li>
</ul>
<pre><code class="java">// 使用tryLock+定时回退
public boolean transfer(Account from, Account to, int amount) {
    long waitTime = 1000; // 1秒超时
    long endTime = System.nanoTime() + waitTime * 1000000;

    while (true) {
        if (from.lock.tryLock()) {
            try {
                if (to.lock.tryLock()) {
                    try {
                        // 执行转账
                        return true;
                    } finally {
                        to.lock.unlock();
                    }
                }
            } finally {
                from.lock.unlock();
            }
        }

        if (System.nanoTime() &gt; endTime) {
            return false;
        }

        Thread.sleep(100); // 短暂休眠
    }
}
</code></pre>
<p>方案二 <strong>设置锁超时</strong></p>
<ul>
<li>使用 <code>tryLock(long timeout, TimeUnit unit)</code> 方法设置获取锁的超时时间</li>
</ul>
<pre><code class="java">if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }
} else {
    // 处理无法获取锁的情况
}
</code></pre>
<h2 id="锁粒度过大"><a href="#锁粒度过大" class="headerlink" title="锁粒度过大"></a>锁粒度过大</h2><p><strong>问题代码</strong>：</p>
<ul>
<li>使用一个锁保护过多的资源或操作，导致并发性能下降。</li>
</ul>
<pre><code class="java">private final ReentrantLock lock = new ReentrantLock();

public void updateUser(User user) {
    lock.lock();
    try {
        // 更新用户基本信息
        updateBasicInfo(user);
        // 更新用户订单
        updateOrders(user);
        // 更新用户地址
        updateAddresses(user);
    } finally {
        lock.unlock();
    }
}
</code></pre>
<p><strong>优化方案</strong>：</p>
<ul>
<li>减小锁粒度，将一个大锁拆分为多个小锁，每个锁保护不同的资源</li>
<li>使用分段锁。对于集合类数据，可以使用分段锁提高并发度</li>
</ul>
<pre><code class="java">private final ReentrantLock basicInfoLock = new ReentrantLock();
private final ReentrantLock ordersLock = new ReentrantLock();
private final ReentrantLock addressesLock = new ReentrantLock();

public void updateUser(User user) {
    basicInfoLock.lock();
    try {
        updateBasicInfo(user);
    } finally {
        basicInfoLock.unlock();
    }

    ordersLock.lock();
    try {
        updateOrders(user);
    } finally {
        ordersLock.unlock();
    }

    addressesLock.lock();
    try {
        updateAddresses(user);
    } finally {
        addressesLock.unlock();
    }
}
</code></pre>
<h2 id="锁泄漏问题"><a href="#锁泄漏问题" class="headerlink" title="锁泄漏问题"></a>锁泄漏问题</h2><p><strong>问题代码</strong>：</p>
<ul>
<li>忘记释放锁，导致其他线程无法获取锁，程序挂起。</li>
</ul>
<pre><code class="java">public class LockLeakExample {
    private final Lock lock = new ReentrantLock();

    public void riskyMethod() throws Exception {
        lock.lock(); // 获取锁
        if (someCondition()) {
            throw new Exception(&quot;Something went wrong&quot;);
            // 如果抛出异常，锁永远不会被释放
        }
        try {
            // 正常操作
        } finally {
            lock.unlock(); // 只有在不抛出异常时才会执行
        }
    }

    private boolean someCondition() {
        return Math.random() &gt; 0.5;
    }
}
</code></pre>
<p><strong>优化方案</strong>：</p>
<ul>
<li>使用 try-finally 确保锁释放</li>
<li>使用 Java 7 的 <code>try-with-resources</code> 模式</li>
</ul>
<pre><code class="java">public class LockLeakSolution {
    private final Lock lock = new ReentrantLock();

    public void safeMethod() throws Exception {
        // 使用自定义的LockResource实现AutoCloseable
        try (LockResource lr = new LockResource(lock)) {
            if (someCondition()) {
                throw new Exception(&quot;Something went wrong&quot;);
            }
            // 正常操作
        } // 自动调用close()释放锁
    }

    private boolean someCondition() {
        return Math.random() &gt; 0.5;
    }

    // 辅助类实现AutoCloseable
    private static class LockResource implements AutoCloseable {
        private final Lock lock;

        public LockResource(Lock lock) {
            this.lock = lock;
            lock.lock(); // 在构造时获取锁
        }

        @Override
        public void close() {
            lock.unlock(); // 在try-with-resources结束时自动释放锁
        }
    }
}
</code></pre>
<h2 id="活锁问题"><a href="#活锁问题" class="headerlink" title="活锁问题"></a>活锁问题</h2><p><strong>问题代码</strong>：</p>
<ul>
<li>线程不断重试某个操作，但始终无法取得进展。</li>
</ul>
<pre><code class="java">public class LiveLockExample {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    public void method1() {
        while (true) {
            if (lock1.tryLock()) {
                try {
                    if (lock2.tryLock()) {
                        try {
                            System.out.println(&quot;method1 成功&quot;);
                            return;
                        } finally {
                            lock2.unlock();
                        }
                    }
                } finally {
                    lock1.unlock();
                }
            }
            // 没有休眠，可能导致CPU高负载
        }
    }

    public void method2() {
        while (true) {
            if (lock2.tryLock()) {
                try {
                    if (lock1.tryLock()) {
                        try {
                            System.out.println(&quot;method2 成功&quot;);
                            return;
                        } finally {
                            lock1.unlock();
                        }
                    }
                } finally {
                    lock2.unlock();
                }
            }
            // 没有休眠，可能导致CPU高负载
        }
    }
}
</code></pre>
<p><strong>优化方案</strong>：</p>
<ul>
<li>引入随机退避：在重试时加入随机延迟</li>
<li>限制重试次数：设置最大重试次数，超过后放弃或采取其他策略</li>
</ul>
<pre><code class="java">public class LiveLockSolution {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();
    private final Random random = new Random();

    // 解决方案1: 引入随机退避
    public void method1WithBackoff() {
        while (true) {
            if (lock1.tryLock()) {
                try {
                    if (lock2.tryLock()) {
                        try {
                            System.out.println(&quot;method1 成功&quot;);
                            return;
                        } finally {
                            lock2.unlock();
                        }
                    }
                } finally {
                    lock1.unlock();
                }
            }
            // 随机休眠避免活锁
            try {
                Thread.sleep(random.nextInt(50));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }

    // 解决方案2: 限制重试次数
    public void method2WithRetryLimit() {
        int retryCount = 0;
        final int maxRetries = 10;

        while (retryCount &lt; maxRetries) {
            if (lock2.tryLock()) {
                try {
                    if (lock1.tryLock()) {
                        try {
                            System.out.println(&quot;method2 成功&quot;);
                            return;
                        } finally {
                            lock1.unlock();
                        }
                    }
                } finally {
                    lock2.unlock();
                }
            }

            retryCount++;
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }

        System.out.println(&quot;method2 达到最大重试次数&quot;);
        // 执行备用方案
    }
}
</code></pre>
<h2 id="饥饿问题"><a href="#饥饿问题" class="headerlink" title="饥饿问题"></a>饥饿问题</h2><p><strong>问题代码</strong>：</p>
<ul>
<li>某些线程长时间无法获取锁，一直处于等待状态。</li>
</ul>
<pre><code class="java">public class StarvationExample {
    private final Lock lock = new ReentrantLock(); // 非公平锁

    public void worker(String name) {
        while (true) {
            lock.lock();
            try {
                System.out.println(name + &quot; 获得锁&quot;);
                Thread.sleep(1000); // 模拟工作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }
    }

    // 多个线程竞争时，某些线程可能长时间无法获取锁
}
</code></pre>
<p><strong>优化方案</strong>：</p>
<ul>
<li>使用公平锁</li>
<li>限制线程持有锁的时间：避免单个线程长时间占用锁</li>
<li>优先级调整。适当调整线程优先级，但要注意过度使用可能导致其他问题</li>
</ul>
<pre><code class="java">// 限制锁持有时间
public class TimeLimitedLockSolution {
    private final Lock lock = new ReentrantLock();
    private static final long MAX_LOCK_HOLD_TIME_MS = 500; // 最大持有锁时间500ms

    public void worker(String name) {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // 尝试获取锁，最多等待200ms
                if (lock.tryLock(200, TimeUnit.MILLISECONDS)) {
                    try {
                        long start = System.currentTimeMillis();
                        System.out.println(name + &quot; 获得锁&quot;);

                        // 模拟工作，但不超过最大持有时间
                        long workTime = Math.min(1000, MAX_LOCK_HOLD_TIME_MS);
                        Thread.sleep(workTime);

                        // 检查是否已经持有锁过长时间
                        if (System.currentTimeMillis() - start &gt; MAX_LOCK_HOLD_TIME_MS) {
                            System.out.println(name + &quot; 即将超时，主动释放锁&quot;);
                            break; // 退出当前工作循环，释放锁
                        }
                    } finally {
                        lock.unlock();
                        System.out.println(name + &quot; 释放锁&quot;);
                    }
                } else {
                    System.out.println(name + &quot; 等待锁超时，将重试&quot;);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        TimeLimitedLockSolution example = new TimeLimitedLockSolution();

        // 创建多个工作线程
        for (int i = 1; i &lt;= 5; i++) {
            String workerName = &quot;Worker-&quot; + i;
            new Thread(() -&gt; example.worker(workerName)).start();
        }
    }
}
</code></pre>
<pre><code class="java">// 优先级调整
public class EnhancedPrioritySolution {
    private final Lock lock = new ReentrantLock(true); // 使用公平锁作为基础
    private static final long PRIORITY_BOOST_THRESHOLD_MS = 2000; // 等待超过2秒提升优先级
    private static final long MAX_WAIT_TIME_MS = 5000; // 最大等待时间5秒

    public void worker(String name, int basePriority) {
        if (basePriority &lt; Thread.MIN_PRIORITY || basePriority &gt; Thread.MAX_PRIORITY) {
            basePriority = Thread.NORM_PRIORITY;
        }

        Thread.currentThread().setPriority(basePriority);
        long waitStartTime = System.currentTimeMillis();
        boolean priorityBoosted = false;

        while (!Thread.currentThread().isInterrupted()) {
            try {
                // 计算剩余等待时间
                long waitedTime = System.currentTimeMillis() - waitStartTime;
                long remainingWaitTime = MAX_WAIT_TIME_MS - waitedTime;

                if (remainingWaitTime &lt;= 0) {
                    System.out.printf(&quot;%s 等待超时(已等待%dms)，放弃本次操作%n&quot;, 
                                     name, waitedTime);
                    break;
                }

                // 动态优先级调整：等待时间超过阈值时提升优先级
                if (!priorityBoosted &amp;&amp; waitedTime &gt; PRIORITY_BOOST_THRESHOLD_MS) {
                    int newPriority = Math.min(basePriority + 1, Thread.MAX_PRIORITY);
                    Thread.currentThread().setPriority(newPriority);
                    priorityBoosted = true;
                    System.out.printf(&quot;%s 已等待%dms，优先级从%d提升到%d%n&quot;,
                                    name, waitedTime, basePriority, newPriority);
                }

                // 尝试获取锁，带有超时
                if (lock.tryLock(100, TimeUnit.MILLISECONDS)) {
                    try {
                        waitStartTime = System.currentTimeMillis(); // 重置等待时间
                        if (priorityBoosted) {
                            Thread.currentThread().setPriority(basePriority); // 恢复原始优先级
                            priorityBoosted = false;
                        }

                        System.out.printf(&quot;%s (优先级:%d) 获得锁，执行工作%n&quot;, 
                                        name, Thread.currentThread().getPriority());
                        Thread.sleep(800); // 模拟工作
                    } finally {
                        lock.unlock();
                        System.out.printf(&quot;%s 释放锁%n&quot;, name);
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        EnhancedPrioritySolution example = new EnhancedPrioritySolution();

        // 创建多个工作线程，设置不同基础优先级
        for (int i = 1; i &lt;= 5; i++) {
            String workerName = &quot;Worker-&quot; + i;
            int priority = i == 3 ? Thread.MAX_PRIORITY : // 一个高优先级线程
                          i == 5 ? Thread.MIN_PRIORITY : // 一个低优先级线程
                          Thread.NORM_PRIORITY;         // 其他普通优先级

            new Thread(() -&gt; example.worker(workerName, priority), workerName).start();
        }
    }
}
</code></pre>
<h2 id="最佳实践总结"><a href="#最佳实践总结" class="headerlink" title="最佳实践总结"></a>最佳实践总结</h2><ol>
<li><strong>总是使用 try-finally 释放锁</strong>，确保锁在任何情况下都能被释放</li>
<li><strong>尽量减小锁的粒度</strong>，只锁定必要的资源</li>
<li><strong>考虑使用更高级的同步工具</strong>，如 CountDownLatch、CyclicBarrier、Semaphore 等</li>
<li><strong>避免在持有锁时调用外部方法</strong>，这可能导致死锁或性能问题</li>
<li><strong>考虑使用并发集合</strong>，如 ConcurrentHashMap，而不是自己实现同步</li>
<li><strong>在适当的时候使用 volatile 变量</strong>，对于简单的状态标志可能不需要完整同步</li>
<li><strong>考虑无锁算法</strong>，如使用 Atomic 类（AtomicInteger, AtomicReference 等）</li>
</ol>
<h1 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h1><h2 id="Timer"><a href="#Timer" class="headerlink" title="Timer"></a>Timer</h2><p><code>Timer</code> 是 Java 提供的一个 <strong>定时任务调度器</strong>，用于在 <strong>指定的时间</strong> 或 <strong>固定的时间间隔</strong> 执行任务。<code>timer.schedule()</code> 是 <code>Timer</code> 的核心方法，用于安排任务的执行。</p>
<h3 id="Timer的基本使用"><a href="#Timer的基本使用" class="headerlink" title="Timer的基本使用"></a>Timer的基本使用</h3><pre><code class="java">Timer timer = new Timer();  // 创建一个定时器
</code></pre>
<ul>
<li><p><strong>守护线程 vs 用户线程</strong>：</p>
<ul>
<li><p><code>Timer</code> 默认使用 <strong>用户线程（非守护线程）</strong>，即使主线程结束，<code>Timer</code> 仍然会运行。</p>
</li>
<li><p>可以使用 <code>Timer(true)</code> 创建 <strong>守护线程</strong>，当所有用户线程结束时，<code>Timer</code> 自动终止：</p>
<pre><code class="java">Timer timer = new Timer(true);  // 守护线程模式
</code></pre>
</li>
</ul>
</li>
</ul>
<p><strong>安排任务执行</strong></p>
<p><code>Timer</code> 提供了多个 <code>schedule()</code> 方法，用于不同场景的任务调度：</p>
<table>
<thead>
<tr>
<th style="text-align:left"><strong>方法</strong></th>
<th style="text-align:left"><strong>作用</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>schedule(TimerTask task, long delay)</code></td>
<td style="text-align:left">延迟 <code>delay</code> 毫秒后执行任务（<strong>单次执行</strong>）</td>
</tr>
<tr>
<td style="text-align:left"><code>schedule(TimerTask task, Date time)</code></td>
<td style="text-align:left">在指定 <code>Date</code> 时间执行任务（<strong>单次执行</strong>）</td>
</tr>
<tr>
<td style="text-align:left"><code>schedule(TimerTask task, long delay, long period)</code></td>
<td style="text-align:left">延迟 <code>delay</code> 毫秒后首次执行，之后每隔 <code>period</code> 毫秒重复执行（<strong>固定延迟</strong>）</td>
</tr>
<tr>
<td style="text-align:left"><code>schedule(TimerTask task, Date firstTime, long period)</code></td>
<td style="text-align:left">在 <code>firstTime</code> 首次执行，之后每隔 <code>period</code> 毫秒重复执行（<strong>固定延迟</strong>）</td>
</tr>
<tr>
<td style="text-align:left"><code>scheduleAtFixedRate(TimerTask task, long delay, long period)</code></td>
<td style="text-align:left">类似 <code>schedule</code>，但采用 <strong>固定速率</strong>（如果任务执行时间超过 <code>period</code>，会立即执行下一次）</td>
</tr>
</tbody>
</table>
<h4 id="Timer-schedule"><a href="#Timer-schedule" class="headerlink" title="Timer.schedule()"></a>Timer.schedule()</h4><p>基本语法：</p>
<pre><code class="java">// 单次任务示例
Timer timer = new Timer();
timer.schedule(
    new TimerTask() {  // 定义任务
        @Override
        public void run() {
            System.out.println(&quot;任务执行！&quot;);
        }
    },
    2000  // 延迟 2 秒执行
);
</code></pre>
<ul>
<li><strong><code>TimerTask</code></strong>：抽象类，表示要执行的任务（类似 <code>Runnable</code>）</li>
<li><strong><code>delay</code></strong>：延迟时间（毫秒），表示任务多久后执行</li>
</ul>
<p><strong>周期性任务示例</strong></p>
<pre><code class="java">Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        System.out.println(&quot;每隔1秒执行一次&quot;);
    }
}, 0, 1000);  // 立即开始，每隔 1000ms 执行
</code></pre>
<h2 id="ScheduledExecutorService"><a href="#ScheduledExecutorService" class="headerlink" title="ScheduledExecutorService"></a>ScheduledExecutorService</h2><p>由于 <code>Timer</code> 的局限性，Java 5 引入了 <code>ScheduledExecutorService</code>（基于线程池），更推荐使用：</p>
<pre><code class="java">ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
executor.schedule(() -&gt; {
    System.out.println(&quot;2秒后执行&quot;);
}, 2, TimeUnit.SECONDS);
</code></pre>
<p><strong>优势</strong>：</p>
<ul>
<li>使用线程池，避免单线程阻塞问题。</li>
<li>支持更灵活的调度（如 <code>scheduleAtFixedRate</code>）。</li>
<li>异常不会影响其他任务。</li>
</ul>
<p><strong>对比</strong></p>
<table>
<thead>
<tr>
<th style="text-align:left"><strong>对比项</strong></th>
<th style="text-align:left"><strong>Timer</strong></th>
<th style="text-align:left"><strong>ScheduledExecutorService</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>线程模型</strong></td>
<td style="text-align:left">单线程</td>
<td style="text-align:left">线程池（可配置多个线程）</td>
</tr>
<tr>
<td style="text-align:left"><strong>异常处理</strong></td>
<td style="text-align:left">异常会终止整个 <code>Timer</code></td>
<td style="text-align:left">异常不影响其他任务</td>
</tr>
<tr>
<td style="text-align:left"><strong>灵活性</strong></td>
<td style="text-align:left">较低（仅支持简单调度）</td>
<td style="text-align:left">高（支持动态调整、复杂调度）</td>
</tr>
<tr>
<td style="text-align:left"><strong>适用场景</strong></td>
<td style="text-align:left">简单的单次或周期性任务</td>
<td style="text-align:left">高并发、复杂的定时任务调度</td>
</tr>
</tbody>
</table>
<ul>
<li><p>如果只是简单的定时任务（如示例中的死锁检测），<code>Timer</code> 足够使用。</p>
</li>
<li><p>如果是生产环境的高并发任务，优先选择 <code>ScheduledExecutorService</code>。</p>
</li>
</ul>
<h2 id="Condition"><a href="#Condition" class="headerlink" title="Condition"></a>Condition</h2><p><code>Condition</code>是Java并发包(<code>java.util.concurrent.locks</code>)中的一个接口，它提供了线程间通信的更精细控制方式，可以替代传统的<code>Object.wait()</code>、<code>Object.notify()</code>和<code>Object.notifyAll()</code>方法。</p>
<p><code>Condition</code>与<code>Lock</code>配合使用，提供了更灵活的线程等待/通知机制。一个<code>Lock</code>可以创建多个<code>Condition</code>对象，允许线程在不同的条件下等待。</p>
<p><strong>创建Condition</strong></p>
<p>通过<code>Lock</code>对象的<code>newCondition()</code>方法创建：</p>
<pre><code class="java">Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
</code></pre>
<h3 id="核心方法"><a href="#核心方法" class="headerlink" title="核心方法"></a>核心方法</h3><p>1、<code>await()</code> - 使当前线程等待</p>
<p>类似于<code>Object.wait()</code>，使当前线程释放锁并等待，直到被通知或中断。</p>
<pre><code class="java">condition.await();
</code></pre>
<p><strong>主要特点和作用</strong></p>
<ol>
<li><strong>释放锁</strong>：调用 <code>await()</code> 会原子性地释放与 Condition 关联的锁</li>
<li><strong>等待通知</strong>：线程进入等待状态，直到以下情况之一发生：<ul>
<li>其他线程调用该条件的 <code>signal()</code> 或 <code>signalAll()</code> 方法</li>
<li>线程被中断</li>
<li>发生虚假唤醒（spurious wakeup）</li>
</ul>
</li>
<li><strong>重新获取锁</strong>：当线程被唤醒后，在从 <code>await()</code> 返回前会重新获取锁</li>
</ol>
<p>典型使用模式：</p>
<pre><code class="java">Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock();
try {
    while (条件不满足) {  // 必须用 while 而不是 if，防止虚假唤醒
        condition.await(); // 条件不满足时等待
    }
    // 执行条件满足后的操作
} finally {
    lock.unlock();
}
</code></pre>
<hr>
<p>2、<code>signal()</code> - 唤醒一个等待线程</p>
<p>类似于<code>Object.notify()</code>，唤醒一个等待在该条件上的线程。</p>
<pre><code class="java">condition.signal();
</code></pre>
<p>3、<code>signalAll()</code> - 唤醒所有等待线程</p>
<p>类似于<code>Object.notifyAll()</code>，唤醒所有等待在该条件上的线程。</p>
<pre><code class="java">condition.signalAll();
</code></pre>
<p>4、<code>awaitUninterruptibly()</code> - 不可中断的等待</p>
<p>使当前线程等待，直到被通知，且不响应中断。</p>
<p>5、<code>awaitNanos(long nanosTimeout)</code> - 限时等待</p>
<p>使当前线程等待，直到被通知、中断或超时。返回剩余时间。</p>
<p>6、<code>awaitUntil(Date deadline)</code> - 绝对时间等待</p>
<p>使当前线程等待，直到被通知、中断或到达指定时间。</p>
<h3 id="Condition-vs-Object监视器方法"><a href="#Condition-vs-Object监视器方法" class="headerlink" title="Condition vs Object监视器方法"></a>Condition vs Object监视器方法</h3><table>
<thead>
<tr>
<th style="text-align:left">特性</th>
<th style="text-align:left">Condition</th>
<th style="text-align:left">Object监视器方法</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">前置条件</td>
<td style="text-align:left">必须持有Lock</td>
<td style="text-align:left">必须持有对象监视器锁</td>
</tr>
<tr>
<td style="text-align:left">多条件支持</td>
<td style="text-align:left">一个Lock可创建多个Condition</td>
<td style="text-align:left">不支持</td>
</tr>
<tr>
<td style="text-align:left">等待队列</td>
<td style="text-align:left">可以有多个等待队列</td>
<td style="text-align:left">只有一个等待队列</td>
</tr>
<tr>
<td style="text-align:left">中断响应</td>
<td style="text-align:left">支持可中断和不可中断等待</td>
<td style="text-align:left">只支持可中断等待</td>
</tr>
<tr>
<td style="text-align:left">超时控制</td>
<td style="text-align:left">支持纳秒级超时和绝对时间等待</td>
<td style="text-align:left">只支持毫秒级超时</td>
</tr>
</tbody>
</table>

        </div>
        <!-- .entry-content -->
        <div class="single-reward">
          <div class="reward-open">赏<div class="reward-main">
              <ul class="reward-row">
                <li class="alipay-code"><img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/donate/AliPayQR.jpg"></li>
                <li class="wechat-code"><img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/donate/WeChanQR.png"></li>
              </ul>
            </div>
          </div>
        </div>
        <div style="text-align:center; width: 100%" class="social-share share-mobile" data-disabled="diandian, tencent"></div>
        <footer class="post-footer">
          <div class="post-lincenses"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank" rel="nofollow"><i class="fa fa-creative-commons" aria-hidden="true"></i> 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a></div>
          <div class="post-tags">
          </div>
          <div class="post-share">
            <div class="social-share sharehidden share-component"></div>
            <i class="iconfont show-share icon-forward"></i>
          </div>
        </footer><!-- .entry-footer -->
      </article>
      <!-- #post-## -->
      <!--<div class="toc" style="background: none;"></div>-->
      <section class="post-squares nextprev">
        
          
            <div class="post-nepre half previous">
          
            <a href="/2024/04/09/JUC学习笔记-异步编程：Future与Callable/" rel="prev">
              <div class="background">
                <img class="lazyload" src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/loader/orange.progress-bar-stripe-loader.svg" data-src="https://images.unsplash.com/photo-1528164344705-47542687000d?w=540" style="width: 100%; height: 100%; object-fit: cover; pointer-events: none;" onerror="imgError(this,3)" src="https://images.unsplash.com/photo-1528164344705-47542687000d?w=540">
              </div>
              <span class="label">
              Previous Post</span>
              <div class="info">
                <h3>
                JUC学习笔记-异步编程：Future与Callable</h3>
                <hr>
              </div>
            </a>
          </div>
        
        
          
            <div class="post-nepre half next">
          
            <a href="/2024/04/02/JUC学习笔记-基础并发工具：Atomic包与CAS/" rel="next">
              <div class="background">
                <img class="lazyload" src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/loader/orange.progress-bar-stripe-loader.svg" data-src="https://images.unsplash.com/photo-1528164344705-47542687000d?w=540" style="width: 100%; height: 100%; object-fit: cover; pointer-events: none;" onerror="imgError(this,3)" src="https://images.unsplash.com/photo-1528164344705-47542687000d?w=540">
              </div>
              <span class="label">
              Next Post</span>
              <div class="info">
                <h3>
                JUC学习笔记-基础并发工具：Atomic包与CAS</h3>
                <hr>
              </div>
            </a>
          </div>
        
      </section>
      <!-- 评论插件valine -->

<div id="vcomments"></div>
<script>
  window.onload = function(){
      var valine = new Valine();
      valine.init({
        el: '#vcomments',
        appId: "VeenC2gYYyfSOq2rcCSmmruy-MdYXbMMI",
        appKey: "F5kjyHdh4akqc7SDmfzQP8Qi",
		notify: false,
		verify: false,
        path: window.location.pathname,
        placeholder: "你是我一生只会遇见一次的惊喜 ...",
		avatar: "monsterid",
		//meta: [nick,mail,link],
		visitor: true,
        recordIP: "true",
		pageSize: "5" || 10,
		serverURLs: "https://VeenC2gY.api.lncldglobal.com"
      });
	//增加以下六行代码去除 power by valine
    var infoEle = document.querySelector('#vcomments .info');
    if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0){
      infoEle.childNodes.forEach(function(item) {
        item.parentNode.removeChild(item);
      });
    }
  }
</script>

      <section class="author-profile">
        <div class="info" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
          <a href="https://blog.xiongtianci.com" class="profile gravatar"><img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/avatar.jpg" itemprop="image" alt="木浅" height="70" width="70"></a>
          <div class="meta">
            <span class="title">Author</span>
            <h3 itemprop="name">
            <a href="https://blog.xiongtianci.com" itemprop="url" rel="author">木浅</a>
            </h3>
          </div>
        </div>
        <hr>
        <p><i class="iconfont icon-write"></i>YOLO</p>
      </section>
    </main><!-- #main -->
  </div><!-- #primary -->
</div>


    </div>    
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="Type something..."/>
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: 'Posts',
            // PAGES: 'Pages',
            CATEGORIES: 'Categories',
            TAGS: 'Tags',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
    <!-- <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2025 天赐<br>
      powered_by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer> -->
<footer id="colophon" class="site-footer" role="contentinfo">
	<div class="site-info">
		<div class="footertext">
			<div class="img-preload">
				<img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@1.0/img/other/wordpress-rotating-ball-o.svg">
				<img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@1.0/img/other/disqus-preloader.svg">
			</div>
			<p class="foo-logo"
				style="background-image: url('https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/img/custom/sakura.svg');">
			</p>
			<div
				style="background-image:linear-gradient(90deg,#6dba82 0,#07b39b 15%,#1098ad 30%,#5073b8 44%,#a166ab 58%,#ef4e7b 72%,#f37055 86%,#f79533 100%);background-size:cover;-webkit-background-clip:text;-webkit-text-fill-color:transparent;user-select:none;margin-top:0.7em;">
				<i>Tip: 本站电脑访问体验更佳耶&nbsp;<i class="fa fa-angellist" style="display:inline"></i></i>
			</div>
			<!-- color: #666666; -->
			<div style="color: #b9b9b9;">&copy;
				2018-2025&nbsp;天赐&nbsp;
			</div>
		</div>
		<!-- 访客统计 -->
		<!--<div id="busuanzi_container"></div>-->
		<!-- 已运行的时间-容器 -->
		<div id="days"></div>
		<div class="footer-device">
			<p id="footer-sponsor">
				<!-- <a href="https://pages.github.com/" target="_blank" alt="GitHub Pages" rel="nofollow"><img
						src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@1.0/img/logo/GitHub.svg" alt="GitHub Pages"
						style="height: 2em; max-height: 2em;" title=""></a>&nbsp;&nbsp;&nbsp; -->
				<!-- <a href="https://coding.net/pages" target="_blank" alt="Coding Pages" rel="nofollow"><img
						src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@1.0/img/logo/Coding.png" alt="Coding Pages"
						style="height: 1.3em; max-height: 1.3em;padding-bottom: 0px;margin-bottom: 0.35em;"
						title=""></a>&nbsp;&nbsp;&nbsp; -->
				<a href="https://www.jsdelivr.com/" target="_blank" alt="Free CDN" rel="nofollow"><img
						src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/img/logo/JsDelivr_Logo.svg" alt="jsDelivr"
						style="height: 2em; max-height: 2em;padding-bottom: 0px;"></a>&nbsp;&nbsp;&nbsp;<a
					href="https://www.google.com/intl/ja/analytics/" target="_blank" alt="Analytics solution"
					rel="nofollow"><img src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/img/logo/Google.svg"
						alt="Google Analytics" style="height: 1.7em; max-height: 1.7em;padding-bottom: 0px;"></a>
			</p>
		</div>
	</div>
	<!-- .site-info -->
</footer>

<!-- <script src="/js/tocbot.js"></script> -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/lib.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/vendor/clipboard.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/InsightSearch.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/jquery.fancybox.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/zoom.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/sakura-app.js"></script>
<!--浏览器搞笑标题-->
<!--<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/title_change.js"></script>-->
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/volantis.min.js"></script>
<!-- Valine -->
<!--<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>-->
<script src='//unpkg.com/valine/dist/Valine.min.js'></script>
<!--<script src='//unpkg.com/valine@1.3.4/dist/Valine.min.js'></script>-->
<!--<script src="//unpkg.com/valine@1.3.7/dist/Valine.min.js"></script>-->
<!-- 不蒜子 网页计数器 -->
<script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script> -->
<script type="text/javascript">
	/* <![CDATA[ */
	if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
		var Poi = {
			"pjax": "1",
			"movies": {
				"url": "https://cdn.jsdelivr.net/gh/tiancixiong/cdn@v3.0",
				"name": "/video/Unbroken.mp4",
				"live": "close"
			},
			"windowheight": "fixed",
			"codelamp": "close",
			"ajaxurl": "",
			"order": "asc",
			"formpostion": "bottom"
		};
	} else {
		var Poi = {
			"pjax": "1",
			"movies": {
				"url": "https://cdn.jsdelivr.net/gh/tiancixiong/cdn@v3.0",
				"name": "/video/Unbroken.mp4",
				"live": "open"
			},
			"windowheight": "auto",
			"codelamp": "close",
			"ajaxurl": "",
			"order": "asc",
			"formpostion": "bottom"
		};
	}
		/* ]]> */
</script>
<script>
	$(document).ready(function () {
		if ($(".toc").length > 0 && document.body.clientWidth > 1200) {
			if ($(".pattern-center").length > 0) { //有图的情况
				tocbot.init({
					// Where to render the table of contents.
					tocSelector: '.toc', // 放置目录的容器
					// Where to grab the headings to build the table of contents.
					contentSelector: '.entry-content', // 正文内容所在
					// Which headings to grab inside of the contentSelector element.
					scrollSmooth: true,
					headingSelector: 'h1, h2, h3, h4, h5', // 需要索引的标题级别
					headingsOffset: -400,
					scrollSmoothOffset: -85
				});
			} else {
				tocbot.init({
					// Where to render the table of contents.
					tocSelector: '.toc', // 放置目录的容器
					// Where to grab the headings to build the table of contents.
					contentSelector: '.entry-content', // 正文内容所在
					// Which headings to grab inside of the contentSelector element.
					scrollSmooth: true,
					headingSelector: 'h1, h2, h3, h4, h5', // 需要索引的标题级别
					headingsOffset: -85,
					scrollSmoothOffset: -85
				});
			}
			var offsetTop = $('.toc').offset().top - 95;
			window.onscroll = function () {
				var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
				if (scrollTop >= offsetTop) {
					$('.toc').addClass('toc-fixed');
				} else {
					$('.toc').removeClass('toc-fixed');
				}
			}
		}
	});
</script>
<!-- 已运行的时间-js -->
<script>
	function show_date_time() {
		window.setTimeout("show_date_time()", 1000);
		// 获得建站时间
		var time = "28/11/2018 15:36:06";
		time = time.replace(/\//g, ':').replace(' ', ':');
		time = time.split(':');
		BirthDay = new Date(time[2], (time[1] - 1), time[0], time[3], time[4], time[5]);

		today = new Date();
		timeold = (today.getTime() - BirthDay.getTime());
		sectimeold = timeold / 1000
		secondsold = Math.floor(sectimeold);
		msPerDay = 24 * 60 * 60 * 1000
		msPerYear = 365 * 24 * 60 * 60 * 1000
		e_yearsold = timeold / msPerYear
		yearsold = Math.floor(e_yearsold);
		//e_daysold = timeold / msPerDay
		e_daysold = timeold/msPerDay - yearsold*365;
		daysold = Math.floor(e_daysold);
		e_hrsold = (e_daysold - daysold) * 24;
		hrsold = setzero(Math.floor(e_hrsold));
		e_minsold = (e_hrsold - hrsold) * 60;
		minsold = setzero(Math.floor((e_hrsold - hrsold) * 60));
		seconds = setzero(Math.floor((e_minsold - minsold) * 60));
		document.getElementById('days').innerHTML = "已在风雨中运行 " + yearsold + " 年 " + daysold + " 天 " + hrsold + " 小时 " + minsold + " 分 " + seconds + " 秒";
	}

	function setzero(i) {
		if (i < 10) {
			i = "0" + i
		};
		return i;
	}
	show_date_time();
</script>
<!-- 访客统计-js -->
<!--<script>
		if(true){
			document.getElementById('busuanzi_container').innerHTML="<span id=\"busuanzi_container_site_pv\">本站总访问量 <span id=\"busuanzi_value_site_pv\"></span> 次</span><span class=\"post-meta-divider\"> | </span><span id=\"busuanzi_container_site_uv\">本站访客数 <span id=\"busuanzi_value_site_uv\"></span> 人</span>";
		}else{
			document.getElementById('busuanzi_container').hidden;
		}
	</script>-->
<!-- 百度统计自动推送 -->
<!--<script>
	(function(){
		var bp = document.createElement('script');
		var curProtocol = window.location.protocol.split(':')[0];
		if (curProtocol === 'https') {
			bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
		}
		else {
			bp.src = 'http://push.zhanzhang.baidu.com/push.js';
		}
		var scriptList = document.getElementsByTagName("script");
		var s = scriptList[0];
		s.parentNode.insertBefore(bp, s);
	})();
	</script>
	-->
    <div class="openNav no-select" style="height: 50px;">
      <div class="iconflat no-select" style="width: 50px; height: 50px;">
        <div class="icon"></div>
      </div>
      <div class="site-branding search-form-submit">
        <i class="iconfont js-toggle-search iconsearch icon-search"></i>
      </div>
    </div>
  </section>
  
  <!-- 实现换肤功能 -->
  <div class="skin-menu no-select" id="mainskin"  style="position: fixed">
    <div class="theme-controls row-container">
        <ul class="menu-list">
            <li id="white-bg"><i class="fa fa-television" aria-hidden="true"></i></li>
            <li id="sakura-bg"> <i class="iconfont icon-sakura"></i></li>
            <li id="gribs-bg"> <i class="fa fa-slack" aria-hidden="true"></i></li>
            <li id="KAdots-bg"> <i class="iconfont icon-dots"></i></li>
            <li id="totem-bg"> <i class="fa fa-optin-monster" aria-hidden="true"></i></li>
            <li id="pixiv-bg"> <i class="iconfont icon-pixiv"></i></li>
            <li id="bing-bg"> <i class="iconfont icon-bing"></i></li>
            <li id="dark-bg"> <i class="fa fa-moon-o" aria-hidden="true"></i></li>
        </ul>
    </div>
</div>

<canvas id="night-mode-cover"></canvas>
<style>
#mainskin{
    position: fixed;
}
</style> 
  <div class="changeSkin-gear no-select">
    <div class="keys" id="setbtn"> <span id="open-skinMenu"> 切换主题 | SCHEME TOOL &nbsp;
	<i class="iconfont icon-gear inline-block rotating"></i> </span></div>
</div>
  
  <div id="mo-nav" class="">
  <div class="m-avatar">
    <img src="https://fastly.jsdelivr.net/gh/tiancixiong/cdn@v1.0/img/custom/avatar.jpg">
  </div>
  <p style="text-align: center; color: #333; font-weight: 900; font-family: 'Ubuntu', sans-serif; letter-spacing: 1.5px">天赐の小站</p>
  <p style="text-align: center; word-spacing: 20px;">
    
  </p>
  <ul id="menu-new-1" class="menu">
    
      <li>
        <a href="/">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-fort-awesome faa-horizontal" aria-hidden="true"></i>
            首页
          </span>
        </a>
        
      </li>
    
      <li>
        <a href="/archives">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-terminal faa-vertical" aria-hidden="true"></i>
            极客
          </span>
        </a>
        
          <ul class="sub-menu">
            
              <li>
                <a href="/categories/技术/">
                  <i class="fa fa-code" aria-hidden="true"></i>
                  技术
                </a>
              </li>
            
              <li>
                <a href="/categories/Linux/">
                  <i class="fa fa-linux" aria-hidden="true"></i>
                  Linux
                </a>
              </li>
            
          </ul>
        
      </li>
    
      <li>
        <a href="/archives">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-slack faa-spin" aria-hidden="true"></i>
            爱好
          </span>
        </a>
        
          <ul class="sub-menu">
            
              <li>
                <a href="/categories/电影/">
                  <i class="fa fa-film" aria-hidden="true"></i>
                  电影
                </a>
              </li>
            
              <li>
                <a href="/categories/日语/">
                  <i class="fa fa-language" aria-hidden="true"></i>
                  日语
                </a>
              </li>
            
          </ul>
        
      </li>
    
      <li>
        <a href="/archives">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-archive faa-ring" aria-hidden="true"></i>
            归档
          </span>
        </a>
        
          <ul class="sub-menu">
            
              <li>
                <a href="/categories/生活/">
                  <i class="fa fa-file-text-o" aria-hidden="true"></i>
                  生活
                </a>
              </li>
            
              <li>
                <a href="/categories/随想/">
                  <i class="fa fa-commenting-o" aria-hidden="true"></i>
                  随想
                </a>
              </li>
            
              <li>
                <a href="/categories/资源/">
                  <i class="fa fa-cloud-download" aria-hidden="true"></i>
                  资源
                </a>
              </li>
            
              <li>
                <a href="/categories/转载/">
                  <i class="fa fa-book" aria-hidden="true"></i>
                  转载
                </a>
              </li>
            
          </ul>
        
      </li>
    
      <li>
        <a href="/comment/">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-pencil-square-o faa-tada" aria-hidden="true"></i>
            留言板
          </span>
        </a>
        
      </li>
    
      <li>
        <a href="/links/">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-link faa-shake" aria-hidden="true"></i>
            友人帐
          </span>
        </a>
        
      </li>
    
      <li>
        <a href="/donate/">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-heart faa-burst" aria-hidden="true"></i>
            赞赏
          </span>
        </a>
        
      </li>
    
      <li>
        <a href="/">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-leaf faa-falling" aria-hidden="true"></i>
            关于
          </span>
        </a>
        
          <ul class="sub-menu">
            
              <li>
                <a href="/about/">
                  <i class="fa fa-meetup" aria-hidden="true"></i>
                  我？
                </a>
              </li>
            
              <li>
                <a href="/theme-sakura/">
                  <i class="fa iconfont icon-sakura" aria-hidden="true"></i>
                  主题
                </a>
              </li>
            
          </ul>
        
      </li>
    
      <li>
        <a href="/atom.xml">
          <span class="faa-parent animated-hover">
            <i class="fa  fa-rss faa-passing" aria-hidden="true"></i>
            RSS
          </span>
        </a>
        
      </li>
    
  </ul>
  <p style="text-align: center; font-size: 13px; color: #b9b9b9;">&copy 2019 hexo-sakura</p>
</div>
<button onclick="topFunction()" class="mobile-cd-top" id="moblieGoTop" title="Go to top" style="display: none;"><i class="fa fa-chevron-up" aria-hidden="true"></i></button>
  <!--<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.css">-->
<!--<script src="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/css/aplayer/APlayer.min.css">
<script src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/aplayer/APlayer.min.js"></script>

<style>
  .aplayer .aplayer-lrc {
    height: 35px;
  }
  .aplayer .aplayer-lrc p{
    font-size: 16px;
    font-weight: 700;
    line-height: 18px !important;
  }
  .aplayer .aplayer-lrc p.aplayer-lrc-current{
    color: #FF1493;
  }
  /*.aplayer.aplayer-narrow .aplayer-body{
    left: -66px !important;
  }*/
  .aplayer.aplayer-fixed .aplayer-lrc {
    display: none;
  }
  .aplayer .aplayer-lrc.aplayer-lrc-hide {
      display:none !important;
  }
  .aplayer.aplayer-fixed .lrc-show {
    display: block;
    background: rgba(255, 255, 255, 0.8);
  }
</style>
<div class="aplayer"

    data-id="7040682880"

    data-server="tencent"

    data-type="playlist"

    data-fixed="true"

    data-autoplay="false"

    data-loop="all"

    data-order="random"

    data-preload="auto"

    data-volume="0.5"

    data-mutex="true"

    data-listFolded="false"

</div>
<!-- Meting 一个支持各种音乐平台(腾讯、网易...)的音乐 API 框架 -->
<!--<script src="https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>-->
<script src="https://cdn.jsdelivr.net/gh/tiancixiong/cdn@sakura-theme/js/aplayer/Meting.min.js"></script>
<script>
  $(function(){
    $('body').on('click', '.aplayer', function(){
      if($('.aplayer-button').hasClass('aplayer-play')) {
        $('.aplayer-lrc').removeClass('lrc-show');
      } else {
        $('.aplayer-lrc').addClass('lrc-show');
      }
    })
  });
</script>
</body>
</html>